前端面霸:一文搞懂虚拟DOM |
您所在的位置:网站首页 › js 删除dom节点 › 前端面霸:一文搞懂虚拟DOM |
一、虚拟 DOM
在React框架中,虚拟 DOM 是由 React.createElement() 或 JSX 语法创建的 JavaScript 对象。 当应用程序的状态发生更改时,它可以在内存中构建新的 DOM 树,与旧的 DOM 树进行比较,以确定需要进行哪些 DOM 操作来更新应用程序的界面。 工作原理虚拟 DOM 的工作原理分为三个步骤: 生成虚拟 DOM 树 比较新旧虚拟 DOM 树以查找差异 根据差异更新实际 DOM 元素React框架使用一种叫做 "diff算法" 的优化算法来查找差异,并使用 "批处理" 技术将多个 DOM 更新操作合并为单个操作来优化性能。 Hello World React Vue // 经过转化后,长这样: { type: 'div', props: { class: 'Index' }, children: [ { type: 'div', children: 'Hello World' }, { type: 'ul', children: [ { type: 'li', children: 'React' }, { type: 'li', children: 'Vue' }, ] } ] } 复制代码在React框架中,每个虚拟DOM节点都有以下属性: type: 节点的类型,例如元素节点、文本节点等。 ref: 节点的引用,用于在React中直接访问DOM节点。 key: 用于帮助React区分不同的子元素,以提高更新性能。 props: 节点的属性,例如元素节点的class、id等属性。 children: 包含节点的子节点的数组,其中子节点可以是其他虚拟DOM节点,也可以是文本节点。如果一个节点没有子节点,则其children属性为空数组。 $$typeof: React使用的一个特殊属性,用于标识该节点是一个合法的React元素,而不是普通的JavaScript对象。 二、与真实 DOM 对比通过各自的创建方式,以打印的方式检查两种 DOM 的区别: const VDOM = React.createElement('div', {}, 'Hello VDOM') const DOM = document.createElement("div"); DOM.innerHTML = 'Hello DOM' console.log(`虚拟DOM:`, VDOM) console.log(`真实DOM:`, DOM) 复制代码 数据结构不同 虚拟 DOM 是 JavaScript 对象 而真实 DOM 是浏览器内部维护的一种数据结构。 操作方式不同 虚拟 DOM 的操作是在 JavaScript 环境下进行的,操作通常不会引起页面的重绘和重排 而真实 DOM 的操作是在浏览器环境下进行的,操作很可能会引起页面的重绘和重排 更新方式不同 虚拟 DOM 更新时,会先生成新的虚拟 DOM 树,然后通过比较新旧虚拟 DOM 树的差异来更新真实 DOM 而真实 DOM 更新时,每次修改都会立即更新 DOM 树 三、虚拟 DOM 的优点 提高性能:浏览器处理 DOM 很慢,处理 JS 对象很快 。 使用虚拟 DOM,可以避免频繁地对实际 DOM 进行操作,从而减少浏览器的重绘和回流,提高应用程序的性能和效率。 简化开发:原生JS很多时候要关注 DOM 操作,对于虚拟 DOM 开发者只需要关注数据和状态的变化,而不必考虑如何手动更新 DOM 。React 会负责一切与 DOM 相关的操作,包括处理事件、调整布局、更新样式等。 跨平台:由于虚拟 DOM 只是一个 JavaScript 对象,因此它可以在不同的平台上运行,例如Web、iOS 和 Android 等。这使得开发人员可以在不同的平台上使用相同的代码库,并且只需根据需要使用不同的渲染器即可。综上所述,虚拟 DOM 可以提高性能、简化开发、跨平台和方便测试等方面的优点,使得现代 Web 应用程序开发更加高效和可靠。 一定能提升性能吗不一定! 虚拟 DOM 的性能优势主要在于能够减少实际 DOM 的操作次数。但是,如果应用程序本身的复杂度不高或者虚拟DOM的实现方式不够优秀,可能无法带来性能提升,甚至会引入额外的性能开销。 它的优势是在于 diff 算法和批量处理策略,将所有的 DOM 操作搜集起来,一次性去改变真实的 DOM ,但在首次渲染上,虚拟 DOM 会多了一层计算,消耗一些性能,所以有可能会比 html 渲染的要慢 总之,虚拟DOM在适当的情况下可以提高性能,但并不是一定能够提升性能,需要根据实际情况进行评估。 四、diff 算法diff 算法是指在比较两棵虚拟DOM树时,通过一系列的算法来计算出它们之间的差异,然后只更新需要更新的部分,从而减少对实际DOM的操作,提高性能和效率。 降低 diff 算法复杂度React 中的 diff 算法并非首创,而是引入,React团队为 diff 算法做出了质的优化: 在计算一颗树转化为另一颗树有哪些改变时,传统的 diff 算法通过循环递归对节点进行依此对比,算法复杂度达到 O(n^ 3) ,也就是说,如果展示一千个节点,就要计算十亿次。 而 Reac t中的 diff 算法,算法复杂度为 O(n) ,即展示一千个节点,只需要计算一千次。 React通过三种策略完成了优化 Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计。 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。 对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。分别对应:tree diff(同级比较)、component diff(组件比较)、element diff(节点比较) 当应用程序的状态发生变化时,虚拟DOM会在内存中构建新的虚拟DOM树,并与之前的虚拟DOM树进行比较,以找出它们之间的差异,然后只更新需要更新的部分,从而提高应用程序的性能和效率。这个过程称为 “协调” 。 Tree difftree diff 是虚拟 DOM 协调过程中的一种算法,用于查找并比较新旧虚拟DOM树之间的差异。它通过深度优先遍历虚拟DOM树,并逐个比较节点来查找差异,并标记需要更新的部分,从而提高应用程序的性能和效率。 Component diffComponent diff算法的实现方式与tree diff算法类似,都是采用深度优先遍历的方式来遍历虚拟DOM树。但是,Component diff算法比tree diff算法更加复杂,因为它不仅要比较虚拟DOM节点之间的差异,还要比较组件的状态和属性。在比较组件时,React会根据组件类型和key值来确定它们是否相同,从而决定是否需要更新组件。 element diffElement diff算法的实现方式比Component diff算法更加简单,它只需要比较同一层级的子节点之间的key值,以确定它们的位置是否有变化。如果子节点的位置没有变化,则只需要比较其它属性是否有变化,并更新需要更新的部分。如果子节点的位置有变化,则需要将原来的子节点移动到新的位置,而不是创建一个新的子节点。 五、虚拟DOM面试题01 | 虚拟DOM是如何提高应用程序性能的? 提高性能的本质都是为了:减少操作真实 DOM 以减少性能消耗, 方法有两类: 通过将 DOM 操作转换为对 JavaScript 对象的操作 因为真实 DOM 的操作会引起页面的重绘和重排,这是非常消耗性能的。而虚拟 DOM 操作只需要更新 JavaScript 对象,不会引起页面的重绘和重排。 通过 diff 算法等优化策略 在更新虚拟 DOM 树时,会通过 diff 算法比较新旧虚拟DOM树的差异,只更新需要更新的部分,从而减少对真实DOM的操作次数。 虚拟 DOM 还使用批处理技术,将多个DOM操作合并为单个操作,从而进一步提高性能。批处理:需要进行多次DOM操作,批处理技术可以将这些操作合并为单个操作,从而减少对真实DOM的操作次数,提高性能和效率。 02 | 为什么处理DOM慢,而处理对象快? 浏览器处理 DOM 很慢的原因主要有以下几点: DOM 操作会引起页面的重绘和重排,这是非常消耗性能的。每次对 DOM 进行修改都需要重新计算布局和重新绘制元素,这个过程非常耗费时间。 DOM 结构是树形结构,它需要通过遍历来查找和访问节点。当 DOM 结构非常庞大时,遍历的时间成本也会相应增加。 DOM 操作涉及到网络请求和 I/O 操作,这些操作通常是异步执行的,需要等待操作完成后才能进行下一步操作。这也会影响到 DOM 操作的性能。相比之下,JS处理对象要快一些的原因主要有以下几点: JS 引擎通常会将对象存储在堆内存中,并使用指针来访问它们。因为堆内存是连续的,所以访问对象的时间复杂度是常数级别的,而不会像 DOM 遍历那样需要花费大量时间。 JS 引擎在对对象进行操作时,通常会将其存储在寄存器或缓存中,这样可以大大提高访问速度。 JS 的对象通常比DOM结构更小,这意味着访问和操作对象所需的数据量更少,也更容易缓存。总之,浏览器处理 DOM 很慢,而 JS 处理对象很快的原因主要在于 DOM 操作涉及到页面布局和渲染等复杂的计算和 I/O 操作,而 JS 操作对象通常只需要访问内存中的指针,并且对象的大小和操作数据量都比 DOM 结构小。 03 | 什么是key值?在React中,为什么需要使用key值? 在 React 中,key 是用来标识列表中每个子元素的唯一标识符。当使用列表渲染(如 'map()' 方法)时,React 会根据每个子元素的 key 值来进行优化,从而提高列表的渲染性能和效率。 React 使用 key 来追踪哪些子元素被修改、添加或删除。当进行列表更新时,React 会首先使用 key 来判断新旧子元素是否相同,从而减少对真实 DOM 的操作。如果没有 key,React 只能通过比较子元素的内容和顺序来判断子元素是否相同,这样会增加 React 的运算负担,降低应用程序的性能。 需要注意的是,key 值必须是唯一的,并且稳定不变的。如果列表中的 key 值发生变化,React 会认为该子元素已经被删除,而不是被更新,这样可能会导致不必要的性能损失。 因此,在使用 key 时,应该选择一个稳定不变的值,如子元素的唯一标识符或索引值。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |